package lab.three.positioning;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;

public class Lab3PositioningActivity extends MapActivity{
	
	public MapView m_mapView;
	public MyItemizedOverlay m_itemizedOverlay;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Log.d("debug-event", "Lab3PositioningActivity onCreate");
        
        m_mapView = (MapView)findViewById(R.id.mapview);
        m_mapView.setBuiltInZoomControls(true);
	    Drawable drawable = this.getResources().getDrawable(R.drawable.androidmarker);
        m_itemizedOverlay = new MyItemizedOverlay(drawable, getApplicationContext());
        
        new MyAsyncTask().execute(); 
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
    {
    	MenuInflater inflater = getMenuInflater();
    	inflater.inflate(R.menu.menu, menu);
    	return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

    	if (item.getItemId() == R.id.update)
    	{
    		Intent intent = new Intent(this, PositionService.class);
    		startService(intent);
    	}
    	else if (item.getItemId() == R.id.updateMap)
    	{
    		m_mapView.requestLayout();
    	}
    	return true;
    }

	@Override
	protected boolean isRouteDisplayed() 
	{
		return false;
	}
	
	private class MyItemizedOverlay extends ItemizedOverlay<OverlayItem>
	{
		private ArrayList<OverlayItem> m_overlays = new ArrayList<OverlayItem>();
		private Context m_context;
		
		public MyItemizedOverlay(Drawable defaultMarker, Context context) 
		{
			super(boundCenterBottom(defaultMarker));
			m_context = context;
		}
		
		@Override
		protected OverlayItem createItem(int i) {
			return m_overlays.get(i);
		}
		
		public void AddOverLay(OverlayItem overlay)
		{
			m_overlays.add(overlay);
			populate();
		}

		@Override
		public int size() {
			return m_overlays.size();
		}
		
		@Override
		protected boolean onTap(int index) 
		{
			OverlayItem item = m_overlays.get(index);
			Toast.makeText(m_context, "Title: " + item.getTitle(), Toast.LENGTH_LONG).show();
			
			return true;
		}
		
		@Override
		public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
				long when) {
			Log.d("debug-event", "In the overlays draw method.");
			return super.draw(canvas, mapView, shadow, when);
		}
	}
	
	private class MyAsyncTask extends AsyncTask<Void, Integer, List<GeoPoint>>
	{
		public List<Overlay> m_mapOverlays;
		

		@Override
		protected List<GeoPoint> doInBackground(Void... params) 
		{
			Log.d("debug-event", "MyAsyncTask doInBackground.");
			
			URL url = null;
			try 
			{
				url = new URL("http://homepage.lnu.se/staff/tblma/race/getpos.php");
			} 
			catch (MalformedURLException e) 
			{
				e.printStackTrace();
				Log.d("debug-event", e.toString());
			}
			
			// Get the SAXParser from the SAXFactory.
			SAXParserFactory spf = SAXParserFactory.newInstance();
			
			SAXParser sp = null;
			
			try 
			{
				sp = spf.newSAXParser();
			} 
			catch (ParserConfigurationException e) 
			{
				e.printStackTrace();
				Log.d("debug-event", e.toString());
			} 
			catch (SAXException e) 
			{
				e.printStackTrace();
				Log.d("debug-event", e.toString());
			}
			
			// Get the XMLReader from the SAXParser.
			XMLReader xr = null;
			
			if (sp != null)
			{
				try 
				{
					xr = sp.getXMLReader();
				} 
				catch (SAXException e) 
				{
					e.printStackTrace();
					Log.d("debug-event", e.toString());
				}
			}
			
			// Create a new ContentHandler and apply it to the XMLReader. 
			MySAXHandler SAXHandler = new MySAXHandler();
			xr.setContentHandler(SAXHandler);
			
			// Parse the XML-data.
			if (url != null)
			{
				try 
				{
					xr.parse(new InputSource(url.openStream()));
				} 
				catch (IOException e) 
				{
					e.printStackTrace();
					Log.d("debug-event", e.toString());
				} 
				catch (SAXException e) 
				{
					e.printStackTrace();
					Log.d("debug-event", e.toString());
				}
			}
			
			Log.d("debug-event", "Time to get the data from the SAXHandler");
			
			// Get the result from the SAXHandler.
			List<GeoPoint> list = SAXHandler.m_list;

			Log.d("debug-event", "Return the list of GeoPoints.");
			return list;
		}
		
		@Override
		protected void onPostExecute(List<GeoPoint> result) 
		{
			Log.d("debug-event", "result.size: " + result.size());
			if (result.size() > 0)
			{
				 m_mapOverlays = m_mapView.getOverlays();

				Log.d("debug-event", "Inside onPostExecute.");
				
				for (int i = 0; i < result.size(); i++)
				{
					GeoPoint p = result.get(i);
					OverlayItem item = new OverlayItem(p, "lat: " + result.get(i).getLatitudeE6() + " lon: " + result.get(i).getLongitudeE6(), "");
					m_itemizedOverlay.AddOverLay(item);
				}
			        
			    m_mapOverlays.add(m_itemizedOverlay);
			    
			    Log.d("debug-event", "Size: " + m_mapOverlays.size());
			    m_mapView.invalidate();
			}
		}
	}
	
	private class MySAXHandler extends DefaultHandler
	{
		List<GeoPoint> m_list = new ArrayList<GeoPoint>();
		
		List<Location> m_locationList = new ArrayList<Location>();
		Location m_location;
		
		boolean m_lat = false;
		boolean m_lon = false;
		boolean m_acc = false;
		boolean m_time = false;
		
		@Override
		public void startDocument() throws SAXException 
		{
			Log.d("debug-event", "SaxHandler startDocument");
			// Some sort of setting up work.
		}
		
		@Override
		public void endDocument() throws SAXException 
		{
			Log.d("debug-event", "SaxHandler endDocument");
			// Some sort of finishing up work.
			
			Log.d("debug-event", "locationList is empty: " + m_locationList.isEmpty());
			
			for (Location loc : m_locationList)
			{
				// If the lat/lon has been left empty my code will set the lan/lat to an ip (if the ip is actually set which it should always be)
				// therefore split at dots and check how many elements it's split into if it's more than two it means that it's an ip so don't add it.
				Pattern p = Pattern.compile("[.]");
				
				String[] temp = p.split(loc.lat);
				Log.d("debug-event", "Length: " + temp.length);
				
				if (temp.length <= 2)
				{
					float fLat = Float.parseFloat(loc.lat);
					float fLon = Float.parseFloat(loc.lon);
						
					int lat = (int)(fLat * 1e6);
					int lon = (int)(fLon * 1e6);
					Log.d("debug-event", "lat: " + lat);
					Log.d("debug-evengt", "lon: " + lon);
					
					GeoPoint point = new GeoPoint(lat, lon);
					Log.d("debug-event", "point: " + point);
					m_list.add(point);
				}
			}
		}
		
		@Override
		public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException 
		{
			// Parse the locations from the web-page.
			if (qName.equalsIgnoreCase("pos"))
			{
				m_location = new Location();
			}
			else if (qName.equalsIgnoreCase("lat"))
			{
				m_lat = true;
			}
			else if (qName.equalsIgnoreCase("lon"))
			{
				m_lon = true;
			}
			else if (qName.equalsIgnoreCase("acc"))
			{
				m_acc = true;
			}
			else if (qName.equalsIgnoreCase("timestamp"))
			{
				m_time = true;
			}
		}
		
		@Override
		public void endElement(String uri, String localName, String qName) throws SAXException 
		{
			Log.d("debug-event", "SaxHandler endElement");
			
			if (qName.equalsIgnoreCase("pos"))
			{
				m_locationList.add(m_location);
			}
			
			// Do something when you reach the end of the element.
		}
		
		@Override
		public void characters(char[] ch, int start, int length) throws SAXException 
		{
			if (m_lat)
			{
				m_location.lat = new String(ch, start, length);
				Log.d("debug-event", "lat: " + new String(ch, start, length));
				m_lat = false;
			}
			if (m_lon)
			{
				m_location.lon = new String(ch, start, length);
				Log.d("debug-event", "lon: " + new String(ch, start, length));
				m_lon = false;
			}			
			if (m_acc)
			{
				m_location.acc = new String(ch, start, length);
				Log.d("debug-event", "acc: " + new String(ch, start, length));
				m_acc = false;
			}
			if (m_time)
			{
				m_location.time = new String(ch, start, length);
				Log.d("debug-event", "time: " + new String(ch, start, length));
				m_time = false;
			}
		}
	}
}